/** 
 * @file ./src/sql/mysql/index.js
 * @fileoverview 该模块用于与MySQL数据库进行交互，提供了执行SQL语句、获取列表数据以及获取分页列表数据的功能。 
 * @author [ZouAnZu] 
 * @version 1.0 
 */ 
 
// 引入mysql2/promise模块，用于与MySQL数据库进行异步交互 
const mysql = require('mysql2/promise'); 
// 引入配置文件，获取数据库相关配置 
const config = require('../config'); 
// 从配置文件中提取MySQL数据库的具体配置 
const databaseConfig = config.dbconfig.mysql; 
 
// 创建一个MySQL连接池，配置连接池参数 
const connPool = mysql.createPool({ 
  // 数据库用户名 
  user: databaseConfig.username, 
  // 数据库密码 
  password: databaseConfig.password, 
  // 数据库主机地址 
  host: databaseConfig.hostname, 
  // 数据库端口 
  port: databaseConfig.port, 
  // 数据库字符集 
  charset: databaseConfig.charset, 
  // 要连接的数据库名称 
  database: databaseConfig.database 
}); 
 
// 监听进程退出事件，在进程退出时关闭连接池 
process.on('exit', async (code) => { 
  try { 
    // 尝试关闭连接池 
    await connPool.end(); 
  } catch (error) { 
    // 如果关闭连接池时出错，这里可以进行更详细的错误处理，目前暂时空着 
  } 
}); 
 
/** 
 * 执行SQL语句的通用函数 
 * @function exec 
 * @param {string} sql - 要执行的SQL语句 
 * @param {array} args - SQL语句中的参数数组 
 * @returns {object} - 包含操作结果的对象，结构为{code: 操作结果码, msg: 操作结果信息, affectedRows: 受影响的行数, action: 操作类型（'update' 或 'insert'）, insertId: 插入操作生成的自增ID} 
 * @description 该函数用于执行各种SQL语句，如插入、更新等操作，并返回操作结果。 
 */ 
const exec = async function (sql, args) { 
  // 初始化结果对象，默认操作成功 
  const result = { code: 1, msg:'success' }; 
  try { 
    // 执行SQL查询，获取结果集 
    const [rows] = await connPool.query(sql, args); 
    // 记录受影响的行数 
    result.affectedRows = rows.affectedRows; 
    // 根据是否有changedRows字段判断操作类型 
    if (rows.changedRows) { 
      result.action = 'update'; 
    } else { 
      result.action = 'insert'; 
    } 
    // 记录插入操作生成的自增ID 
    result.insertId = rows.insertId; 
    // 返回操作结果 
    return result; 
  } catch (e) { 
    // 如果发生错误，记录错误信息 
    console.log(e.sqlMessage); 
    result.affectedRows = 0; 
    result.msg = e.sqlMessage; 
    result.code = 0; 
    // 返回包含错误信息的结果 
    return result; 
  } 
}; 
 
/** 
 * 获取列表数据的函数 
 * @function getList 
 * @param {string} sql - 用于查询列表的SQL语句 
 * @param {array} args - SQL语句中的参数数组 
 * @returns {object} - 包含查询结果的对象，结构为{code: 操作结果码, data: {recordset: 查询结果数组, total: 查询结果总数}, msg: 操作结果信息} 
 * @description 该函数执行SQL查询并返回列表数据，同时返回数据总数。 
 */ 
const getList = async function (sql, args) { 
  // 初始化结果对象，默认操作成功 
  const result = { code: 1, data: { recordset: [], total: 0 } }; 
  try { 
    // 执行SQL查询，获取结果集和字段信息 
    const [rows, _] = await connPool.query(sql, args); 
    // 记录查询结果的总数 
    result.data.total = rows.length; 
    // 将查询结果复制到recordset数组中 
    result.data.recordset = [...rows]; 
  } catch (e) { 
    // 如果发生错误，记录错误信息 
    result.msg = e.sqlMessage; 
    result.code = 0; 
  } 
  // 返回查询结果 
  return result; 
}; 
 
/** 
 * 获取分页列表数据的函数 
 * @function getPageList 
 * @param {object} sqls - 包含两个SQL语句和对应参数的对象，结构为{sql1: '查询总数的SQL', args1: [查询总数的参数], sql2: '查询分页数据的SQL', args2: [查询分页数据的参数]} 
 * @returns {object} - 包含分页查询结果的对象，结构为{code: 操作结果码, data: {recordset: 分页查询结果数组, total: 数据总数}, msg: 操作结果信息} 
 * @description 该函数先查询数据总数，再根据总数查询分页数据，返回分页后的结果。 
 */ 
const getPageList = async function (sqls) { 
  // 初始化结果对象，默认操作成功 
  const result = { code: 1, data: { recordset: [], total: 0 } }; 
  // 先查询总数 
  const totals = await getList(sqls.sql1, sqls.args1); 
  if (totals.data.total > 0) { 
    // 如果总数大于0，再查询分页数据 
    const rows = await getList(sqls.sql2, sqls.args2); 
    // 记录总数 
    result.data.total = totals.data.recordset[0].total; 
    // 记录分页数据 
    result.data.recordset = [...rows.data.recordset]; 
  } 
  // 返回分页查询结果 
  return result; 
}; 
 
// 测试函数，用于测试getList函数 
async function t() { 
  const s = await getList('select * from mg_members where username=? and password=?', ['admin', '1234']); 
  console.log(s); 
} 
// 取消注释以运行测试函数 
// t() 
 
// 导出模块，包含连接池、获取列表、获取分页列表、执行SQL语句的函数以及数据库配置 
module.exports = { 
  connPool, 
  getList, 
  getPageList, 
  exec, 
  databaseConfig 
}; 